home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
NetNews Offline 2
/
NetNews Offline Volume 2.iso
/
news
/
comp
/
std
/
c
/
190
< prev
next >
Wrap
Internet Message Format
|
1996-08-06
|
14KB
Path: solon.com!not-for-mail
From: seebs@solutions.solon.com (Peter Seebach)
Newsgroups: comp.lang.c.moderated,comp.lang.c,comp.std.c
Subject: Re: Perhaps it's time the C community *did* something about bad books.
Date: 25 Jan 1996 21:06:23 -0600
Organization: Usenet Fact Police (Undercover)
Approved: seebs
Message-ID: <4e9gff$9n9@solutions.solon.com>
References: <4e07lv$adu@solutions.solon.com> <4e5ooa$6b5@solutions.solon.com> <4e9f08$9br@solutions.solon.com>
NNTP-Posting-Host: solutions.solon.com
In article <4e9f08$9br@solutions.solon.com>,
Scott McMahan - Softbase Systems <softbase@mercury.interpath.com> wrote:
>Not exactly. This is actually the review of the ANSI C standard.
>The "review" errs on the side of being way too critical, and I've
>seen it being debunked in part, but the parts that are debunked
>never seem to be posted with the review anywhere. It's one of those
>things that will endure forever.
Well, I went through it, and I saw nothing in it that was incorrect.
I have the annotated standard, and it's pretty poorly annotated, IMHO.
>I did not see the post that listed errors in C: TCR. I'm interested
>in reading it.
I didn't list them, I just said there were some. It's about 8k/250
lines, and it is pathetically far from complete. In a letter to the
editor at O-MGH, I mentioned several types of errors, so I found about
2-5 examples of each. It took about 45 minutes, including skimming
trying to find an offensively bad misstatement of how precedence
works, which claims that
x = *p * (*p++);
is legal. (And not even because of the parens, but rather, because
it's on the right. Despite the correct statement about OOE earlier.)
>I agree that we should all make Osborne aware of all the errors in
>Mr. Schildt's book so that he can make them better in future
>editions. I was very disappointed in the 3rd Ed. compared to
>the 2nd.
He corrected at least one error; on or about page 53, the 2nd edition
had "i <> 1" and the 3rd has "i != 1".
>On the other hand,
>the third edition seems to have been released in extreme secrecy since I
>learned about it only though a McGraw-Hill book-of-the-month club ad.
I agree; I only saw it last week in a bookstore for the first time.
>What's new? The third edition is surprisingly unchanged. Instead of
>taking the chance to reflect on which chapters he has written in his
>almost 10 years of writing on C and picking the ones that would be most
>useful to an ANSI C programmer, Schildt has instead placed chapters that
>have little to do with a complete reference, including a tacky
>self-promotion.
This is sadly true; a large number of obvious errors have survived.
Some are simply utterly stupid; the claim that you must use feof() to
detect EOF on a binary file, since "EOF is an integer". (Just like
the ones returned by getchar(), which spends the entire book being
returned into a char.) I will not insult the intelligence of the
reader by explaining this, suffice it to say I nearly fell out of
my chair laughing at it.
>Unless Schildt starts trying to find what people want and starts
>remembering why he wrote C: The Complete Reference in the first place,
>he and Osborne are going to have a hard time selling books with ads for
>other books instead of content and using Schildt's name. Schildt is
>already known as a schmuck among real C programmers, deservedly or not,
>and pretty soon everyone will be calling him the "recognized authority"
>on self-promotion and hot air. Either Schildt or McGraw-Hill appears to
>be damaging Schildt's already very shakey reputation beyond repair for
>small short-term gain. I don't know why, is Osborne in some kind of
>financial trouble? They should be trying to build a reputation for
>quality.
*sigh*
A minor nit; he lists quicksort as generally the best sort known.
I have written the publisher a list (enclosed at the bottom of this
post) of errors, and pointed out that this is really bad. The editor
I corresponded with (scottr@crl.com) said he'd run these by Herb to
see if Schildt would appreciate a bit of technical editing.
I have been informed that they are no longer using the technical editor
who was involved with this book, which really doesn't explain how
this garbage survived 3 editions.
>Unfortunately for me, I will probably never order another edition of
>this book, unless the concerns raised here are directly addressed. I'm
>very disenchanted with this book, and will look elsewhere for my
>reference material.
I would never have gotten it if I weren't planning to offer the publisher
"reasonable" rates on the technical editing the book desperately needs.
Feel free to write the editor with comments, positive or negative,
about my ability to improve on this work. (Or me, for that matter.)
Enclosed please find the (mildly vitriolic in places) comments I have
on a representative set of examples. I am far from exhasting what I
saw; I just wanted a good representative set.
Newbies to C: Take the time to read through these, especially if you
have the book. Some of these errors could cost you hours or days of
trying to figure out a problem.
---
I am not including "bad style", but there are a few of those (gets is
strongly depracated, and many programs don't output the last newline,
probably because MS-DOS prints an extra one before the prompt.)
Please pardon typos, and even the possible errors; I have not taken the time
to verify a couple of things. For a serious, aimed-at-publication effort,
I would, of course, take the time to bring the questionable points to the
attention of people in comp.std.c, or otherwise cross-reference the work.
As is, I'm just using memory and the Standard to compare.
Flat contradictions of ANSI's standard.
Page 163
"You may also declare main() as void if it does
not return a value."
Specifically untrue. ANSI mandates two declarations for main, and
says that main may have declarations compatible with those. Both
return int.
Page 434
"free() must only be called with a pointer that was
previously allocated with one of the dynamic allocation
system's functions (either malloc(), realloc(), or
calloc())."
Also specifically untrue. ANSI states that free(NULL) is legal and
has no effect. (Also note that it must be called with a pointer
*to space previously allocated*, not with a pointer previously
allocated, and that the pointer must not have been already freed
or passed to realloc().)
Page 314
"However, since EOF is a valid integer value, you must use
feof() to check for end-of-file when working with binary
files."
Not merely a little bit untrue, but utterly wrong, and specifically
missing the point of the rule (correctly stated) about returning
the char as "unsigned char converted to int" (actually stated
in the standard in 7.9.7.1, under fgetc()).
Since EOF is a *NEGATIVE* integral constant, it can *NEVER* compare
equal to *ANY* unsigned char. When you are reading from a binary
file, the values you get will *never* compare equal to EOF, until
getchar() returns EOF because the file is empty.
This correlates with a mistake made in all of the examples where
loops break on '$', 'A', or ' ' because the return from getchar() is
immediately put into a char variable.
This is a more serious flaw than many, because it results in poorly
written, inefficient code.
(Couple this with the consistent attempts to use feof() to see if
the *next* read will fail, when in fact feof() only returns true
when the *PREVIOUS* read failed, and you get a completely wrong
description of the standard I/O library.)
Also, several of the programs given loop forever if an end of
file is reached, because EOF is not checked for in a loop.
Page 284
All of the header files are listed in capitals; the standard
specifies them in lower case. It is not required that a
C compiler reject all-caps, but nor is it required that it
accept them.
Flat contradictions of POSIX, in the discussion of open/read/write.
Page 253
"In most implementations, the operation fails if the file
specified in the open statement does not exist on the disk."
To the best of my knowledge, POSIX (the standard for the open()
call) documents and requires the functionality of the O_CREAT flag.
[I spelled that as "C_CREAT" in the original. Oops. -seebs]
Undefined behavior/illegal code.
Page 247
The stream fp is opened with mode "r", the mode to open a text file.
Then, fseek is called on fp, with the 2nd argument not a value
returned by a previous call to ftell. (ANSI 7.9.9.2, "For a text
stream, either offset shall be zero, or offset shall be a value
returned by an earlier call to the ftell function on the same stream
and whence shall be SEEK_SET.")
Page 63
If scanf fails, the variable guess is referenced before it has been
initialized; accessing an uninitialized object introduces
undefined behavior.
Page 283
>#include <string.h>
>
>char s1[] = "hello ";
>char s2[] = "there.";
>
>void main(void)
>{
> int p;
>
> p = strcat(s1, s2);
>}
It is correctly noted that this generates a warning. Not mentioned
is that it's illegal; although s1[] is a modifiable array, it is
an array large enough to hold "hello " (and the terminating NUL),
so it has room for 7 bytes. The strcat overflows the array, producing
undefined behavior.
Page 735
This is spectacularly wrong; the "corrected"
"x = *p * (*p++);"
is *EXACTLY* equivalent in terms of C; as correctly noted earlier,
the order of evaluation *IS NOT SPECIFIED*.
The code is still illegal (p is used to determine *p on the left
of the *, as well as modified on the right), and the parentheses
aren't affecting the code at all.
In this code, p can be incremented anywhere in the line; the only
requirement would be that the value of (*p++) be the same as
the value of (*p) before the increment. It is *not* specified
whether the other *p happens before or after the increment.
In fact, because the code modifies an object (p) and uses the value
of the object to do something other than determine the new value
(The first "*p"), it is *illegal*. Completely; a compiler is allowed
to reject the code, and many will produce surprising results from
this operation.
This is not merely wrong, it's wrong *while discussing the problem*,
which is doubly bad.
Code which does not do what it says it does.
Page 333
>sprintf("%s %d %c", "one", 2, 3);
The result would be "one 2 " and then a control-c, not "one 2 3".
(Presumably, "3" should have been "'3'".)
Page 53
>printf("%f", sizeof f);
Clearly wrong; sizeof is not a double or float.
Page 53
>printf("%d", sizeof(int));
Subtly wrong; sizeof is a size_t, which may not be any sort of int.
The only safe way to do this is
>printf("%ul", (unsigned long) sizeof(int));
While this is larger, a clear explanation of why it is required will
go a long way towards helping people understand C.
Page 53 (This one's popular)
>/* Write 6 integers to a disk file. */
>void put_rec(int rec[6], FILE *fp)
>{
> int len;
>
> len = fwrite(rec, sizeof rec, 1, fp);
> if (len != 1) printf("write error");
>}
Incorrect. As correctly noted elsewhere, when "int rec[6]" is an
argument to a function, it actually specifies a pointer-to-int,
not an array[6]-of-int. sizeof rec is sizeof(int *) here, and this
code works only if sizeof(int *) is precisely 6 times sizeof(int).
(Not impossible, but hardly likely.)
Further, who said fp was a disk file? fp could be stdout.
Inaccurate or misleading explanations.
Page 132
"After the assignment, p points to the first 1000 bytes of
free memory."
No, p points to at least 1000 bytes of allocated space, which is
not free memory. There is also no reason to assume it was the
"first" 1000 bytes; top-down allocation is not atypical, and
further, there's no reason to assume this code fragment runs in
isolation.
Page 197
It is redundant to give a size of char in bytes as 1 as an
"assumption" - it's the definition, sizeof() gives the size
in *chars*.
Page 162
Functions are not of type void; functions are of various types,
called collectively the function types. A function may have a
return of type void, which means that its type is something like
"function taking (...) and returning void".
Page 59
"This shorthand works for all the binary operators..."
[Meaning op=, ala +=, -=... -seebs]
No, it doesn't. It doesn't work for ".", "->", "&&", or "||".
Page 33
"static Global Variables" [heading]
No such thing. A static variable outside of a function has file
scope, which is distinct from global scope.
Explanations of a DOS-specific feature as "how C works".
Page 19
"In general, negative numbers are represented using the
two's complement approach..."
This is not a C feature. It is a common implementation, but it is
specifically not required.
Page 131
"Memory allocated by C's dynamic allocation functions is
obtained from the <i>heap</i> -- the region of free memory
that lies between your program and its permanent storage
area and the stack."
C does not specify that there is a stack - only that functions can
call each other. The "heap" is a DOS term, and the layout is not
a part of the C language. It is not atypical for the layout to be
radically different, and certainly, there is no call for describing
a specific choice as "what happens".
---cut here
*sigh*
-seebs
(still hypothetically working on my own reference manual, but the chances
of my getting anywhere until I have enough money and time are quite low.
Donations cheerfully accepted. <- blatant plug!)
--
Peter Seebach - seebs@solon.com - Copyright 1995 Peter Seebach.
C/Unix proto-wizard -- C/Unix questions? Send mail for help. No, really!
Using trn? Weird new newsgroup problem? I know the fix! Email me!
The *other* C FAQ - ftp taniemarie.solon.com /pub/c/afq - Not A Flying Toy